#pragma once

#include <memory>
#include <vector>

#include "common/hash_util.h"
#include "planner/operator.h"
#include "planner/operator_visitor.h"

struct RangeTblEntry;

namespace optimizer {

/**
 * Physical operator for sequential scan
 */
class PhysicalSeqScan : public Operator {
 public:
  static constexpr const OperatorType TYPE = OperatorType::PhysicalSeqScan;
  explicit PhysicalSeqScan(RangeTblEntry *rte) : Operator(OperatorType::PhysicalSeqScan), rte_(rte) {}

  std::shared_ptr<Operator> Copy() const override;

  bool operator==(const Operator &r) const override;

  hash_t Hash() const override;

  Oid GetTableOID() const;

  std::string ToString() const override { return std::format("(seqscan: )"); }

  void Accept(OperatorVisitor *v) override { v->Visit(this); }

  RangeTblEntry *GetRangeTblEntry() const { return rte_; }

 private:
  RangeTblEntry *rte_;
};

/**
 * Physical operator for ORDER BY
 */
class OrderBy : public Operator {
 public:
  static constexpr const OperatorType TYPE = OperatorType::OrderBy;
  OrderBy() : Operator(OperatorType::OrderBy) {}

  std::shared_ptr<Operator> Copy() const override;

  std::string ToString() const override { return std::format("(order: )"); }

  bool operator==(const Operator &r) const override;
  hash_t Hash() const override;
  void Accept(OperatorVisitor *v) override { v->Visit(this); }
};

/**
 * Physical operator for Limit
 */
class Limit : public Operator {
 public:
  static constexpr const OperatorType TYPE = OperatorType::Limit;
  Limit() : Operator(OperatorType::Limit) {}

  std::shared_ptr<Operator> Copy() const override;

  bool operator==(const Operator &r) const override;
  hash_t Hash() const override;

  size_t GetOffset() const { return offset_; }

  std::string ToString() const override { return std::format("(limit: )"); }
  void Accept(OperatorVisitor *v) override { v->Visit(this); }

  size_t GetLimit() const { return limit_; }

  size_t offset_;

  size_t limit_;

  List *sort_exprs_;

  std::vector<optimizer::OrderByOrderingType> sort_directions_;
};

}  // namespace optimizer
